From 62acb8067127ec83476e016796a8caa95ef485fc Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 4 Apr 2019 18:40:34 +0100 Subject: [PATCH] Port GtkGrid to use GtkGridLayout --- gtk/gtkgrid.c | 1958 ++++++++----------------------------------------- 1 file changed, 291 insertions(+), 1667 deletions(-) diff --git a/gtk/gtkgrid.c b/gtk/gtkgrid.c index 68c66adb52..9d4e472559 100644 --- a/gtk/gtkgrid.c +++ b/gtk/gtkgrid.c @@ -22,14 +22,15 @@ #include "gtkgrid.h" -#include "gtkorientableprivate.h" -#include "gtksizerequest.h" -#include "gtkwidgetprivate.h" #include "gtkcontainerprivate.h" #include "gtkcsspositionvalueprivate.h" -#include "gtkstylecontextprivate.h" -#include "gtkprivate.h" +#include "gtkgridlayout.h" +#include "gtkorientableprivate.h" #include "gtkintl.h" +#include "gtkprivate.h" +#include "gtksizerequest.h" +#include "gtkstylecontextprivate.h" +#include "gtkwidgetprivate.h" /** @@ -56,99 +57,12 @@ * GtkGrid uses a single CSS node with name grid. */ -typedef struct _GtkGridChild GtkGridChild; -typedef struct _GtkGridChildAttach GtkGridChildAttach; -typedef struct _GtkGridRowProperties GtkGridRowProperties; -typedef struct _GtkGridLine GtkGridLine; -typedef struct _GtkGridLines GtkGridLines; -typedef struct _GtkGridLineData GtkGridLineData; -typedef struct _GtkGridRequest GtkGridRequest; - -struct _GtkGridChildAttach -{ - gint pos; - gint span; -}; - -struct _GtkGridRowProperties -{ - gint row; - GtkBaselinePosition baseline_position; -}; - -static const GtkGridRowProperties gtk_grid_row_properties_default = { - 0, - GTK_BASELINE_POSITION_CENTER -}; - -struct _GtkGridChild -{ - GtkGridChildAttach attach[2]; -}; - -#define CHILD_LEFT(child) ((child)->attach[GTK_ORIENTATION_HORIZONTAL].pos) -#define CHILD_WIDTH(child) ((child)->attach[GTK_ORIENTATION_HORIZONTAL].span) -#define CHILD_TOP(child) ((child)->attach[GTK_ORIENTATION_VERTICAL].pos) -#define CHILD_HEIGHT(child) ((child)->attach[GTK_ORIENTATION_VERTICAL].span) - -/* A GtkGridLineData struct contains row/column specific parts - * of the grid. - */ -struct _GtkGridLineData -{ - gint16 spacing; - guint homogeneous : 1; -}; - -struct _GtkGridPrivate +typedef struct { - GList *row_properties; + GtkLayoutManager *layout_manager; GtkOrientation orientation; - gint baseline_row; - - GtkGridLineData linedata[2]; -}; -typedef struct _GtkGridPrivate GtkGridPrivate; - -#define ROWS(priv) (&(priv)->linedata[GTK_ORIENTATION_HORIZONTAL]) -#define COLUMNS(priv) (&(priv)->linedata[GTK_ORIENTATION_VERTICAL]) - -static GQuark child_data_quark = 0; - -/* A GtkGridLine struct represents a single row or column - * during size requests - */ -struct _GtkGridLine -{ - gint minimum; - gint natural; - gint minimum_above; - gint minimum_below; - gint natural_above; - gint natural_below; - - gint position; - gint allocation; - gint allocated_baseline; - - guint need_expand : 1; - guint expand : 1; - guint empty : 1; -}; - -struct _GtkGridLines -{ - GtkGridLine *lines; - gint min, max; -}; - -struct _GtkGridRequest -{ - GtkGrid *grid; - GtkGridLines lines[2]; -}; - +} GtkGridPrivate; enum { @@ -159,30 +73,18 @@ enum PROP_COLUMN_HOMOGENEOUS, PROP_BASELINE_ROW, N_PROPERTIES, + + /* GtkOrientable */ PROP_ORIENTATION }; static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; -enum -{ - CHILD_PROP_0, - CHILD_PROP_LEFT_ATTACH, - CHILD_PROP_TOP_ATTACH, - CHILD_PROP_WIDTH, - CHILD_PROP_HEIGHT, - N_CHILD_PROPERTIES -}; - -static GParamSpec *child_properties[N_CHILD_PROPERTIES] = { NULL, }; - G_DEFINE_TYPE_WITH_CODE (GtkGrid, gtk_grid, GTK_TYPE_CONTAINER, G_ADD_PRIVATE (GtkGrid) G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)) -static void gtk_grid_row_properties_free (GtkGridRowProperties *props); - static void gtk_grid_get_property (GObject *object, guint prop_id, @@ -199,1398 +101,228 @@ gtk_grid_get_property (GObject *object, break; case PROP_ROW_SPACING: - g_value_set_int (value, COLUMNS (priv)->spacing); - break; - - case PROP_COLUMN_SPACING: - g_value_set_int (value, ROWS (priv)->spacing); - break; - - case PROP_ROW_HOMOGENEOUS: - g_value_set_boolean (value, COLUMNS (priv)->homogeneous); - break; - - case PROP_COLUMN_HOMOGENEOUS: - g_value_set_boolean (value, ROWS (priv)->homogeneous); - break; - - case PROP_BASELINE_ROW: - g_value_set_int (value, priv->baseline_row); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gtk_grid_set_orientation (GtkGrid *grid, - GtkOrientation orientation) -{ - GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); - - if (priv->orientation != orientation) - { - priv->orientation = orientation; - _gtk_orientable_set_style_classes (GTK_ORIENTABLE (grid)); - - g_object_notify (G_OBJECT (grid), "orientation"); - } -} - -static void -gtk_grid_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkGrid *grid = GTK_GRID (object); - - switch (prop_id) - { - case PROP_ORIENTATION: - gtk_grid_set_orientation (grid, g_value_get_enum (value)); - break; - - case PROP_ROW_SPACING: - gtk_grid_set_row_spacing (grid, g_value_get_int (value)); + g_value_set_int (value, gtk_grid_layout_get_row_spacing (GTK_GRID_LAYOUT (priv->layout_manager))); break; case PROP_COLUMN_SPACING: - gtk_grid_set_column_spacing (grid, g_value_get_int (value)); + g_value_set_int (value, gtk_grid_layout_get_column_spacing (GTK_GRID_LAYOUT (priv->layout_manager))); break; case PROP_ROW_HOMOGENEOUS: - gtk_grid_set_row_homogeneous (grid, g_value_get_boolean (value)); + g_value_set_boolean (value, gtk_grid_layout_get_row_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager))); break; case PROP_COLUMN_HOMOGENEOUS: - gtk_grid_set_column_homogeneous (grid, g_value_get_boolean (value)); - break; - - case PROP_BASELINE_ROW: - gtk_grid_set_baseline_row (grid, g_value_get_int (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static GtkGridChild * -get_grid_child (GtkWidget *widget) -{ - return (GtkGridChild *) g_object_get_qdata (G_OBJECT (widget), child_data_quark); -} - -static void -gtk_grid_get_child_property (GtkContainer *container, - GtkWidget *child, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GtkGridChild *grid_child; - - grid_child = get_grid_child (child); - - if (grid_child == NULL) - { - GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); - return; - } - - switch (property_id) - { - case CHILD_PROP_LEFT_ATTACH: - g_value_set_int (value, CHILD_LEFT (grid_child)); - break; - - case CHILD_PROP_TOP_ATTACH: - g_value_set_int (value, CHILD_TOP (grid_child)); - break; - - case CHILD_PROP_WIDTH: - g_value_set_int (value, CHILD_WIDTH (grid_child)); - break; - - case CHILD_PROP_HEIGHT: - g_value_set_int (value, CHILD_HEIGHT (grid_child)); - break; - - default: - GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); - break; - } -} - -static void -gtk_grid_set_child_property (GtkContainer *container, - GtkWidget *child, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkGrid *grid = GTK_GRID (container); - GtkGridChild *grid_child; - - grid_child = get_grid_child (child); - - if (grid_child == NULL) - { - GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); - return; - } - - switch (property_id) - { - case CHILD_PROP_LEFT_ATTACH: - CHILD_LEFT (grid_child) = g_value_get_int (value); - break; - - case CHILD_PROP_TOP_ATTACH: - CHILD_TOP (grid_child) = g_value_get_int (value); - break; - - case CHILD_PROP_WIDTH: - CHILD_WIDTH (grid_child) = g_value_get_int (value); - break; - - case CHILD_PROP_HEIGHT: - CHILD_HEIGHT (grid_child) = g_value_get_int (value); - break; - - default: - GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); + g_value_set_boolean (value, gtk_grid_layout_get_column_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager))); break; - } - - if (_gtk_widget_get_visible (child) && - _gtk_widget_get_visible (GTK_WIDGET (grid))) - gtk_widget_queue_resize (child); -} - -static void -gtk_grid_finalize (GObject *object) -{ - GtkGrid *grid = GTK_GRID (object); - GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); - - g_list_free_full (priv->row_properties, (GDestroyNotify)gtk_grid_row_properties_free); - - G_OBJECT_CLASS (gtk_grid_parent_class)->finalize (object); -} - -static void -grid_attach (GtkGrid *grid, - GtkWidget *widget, - gint left, - gint top, - gint width, - gint height) -{ - GtkGridChild *child; - - child = g_new (GtkGridChild, 1); - CHILD_LEFT (child) = left; - CHILD_TOP (child) = top; - CHILD_WIDTH (child) = width; - CHILD_HEIGHT (child) = height; - - g_object_set_qdata_full (G_OBJECT (widget), child_data_quark, child, g_free); - gtk_widget_set_parent (widget, GTK_WIDGET (grid)); -} - -/* Find the position 'touching' existing - * children. @orientation and @max determine - * from which direction to approach (horizontal - * + max = right, vertical + !max = top, etc). - * @op_pos, @op_span determine the rows/columns - * in which the touching has to happen. - */ -static gint -find_attach_position (GtkGrid *grid, - GtkOrientation orientation, - gint op_pos, - gint op_span, - gboolean max) -{ - GtkGridChildAttach *attach; - GtkGridChildAttach *opposite; - GtkWidget *child; - gint pos; - gboolean hit; - - if (max) - pos = -G_MAXINT; - else - pos = G_MAXINT; - - hit = FALSE; - - for (child = gtk_widget_get_first_child (GTK_WIDGET (grid)); - child != NULL; - child = gtk_widget_get_next_sibling (child)) - { - GtkGridChild *grid_child = get_grid_child (child); - - attach = &grid_child->attach[orientation]; - opposite = &grid_child->attach[1 - orientation]; - - /* check if the ranges overlap */ - if (opposite->pos <= op_pos + op_span && op_pos <= opposite->pos + opposite->span) - { - hit = TRUE; - - if (max) - pos = MAX (pos, attach->pos + attach->span); - else - pos = MIN (pos, attach->pos); - } - } - - if (!hit) - pos = 0; - - return pos; -} - -static void -gtk_grid_add (GtkContainer *container, - GtkWidget *child) -{ - GtkGrid *grid = GTK_GRID (container); - GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); - gint pos[2] = { 0, 0 }; - - pos[priv->orientation] = find_attach_position (grid, priv->orientation, 0, 1, TRUE); - grid_attach (grid, child, pos[0], pos[1], 1, 1); -} - -static void -gtk_grid_remove (GtkContainer *container, - GtkWidget *child) -{ - GtkGrid *grid = GTK_GRID (container); - gboolean was_visible; - - was_visible = _gtk_widget_get_visible (child); - gtk_widget_unparent (child); - - if (was_visible && _gtk_widget_get_visible (GTK_WIDGET (grid))) - gtk_widget_queue_resize (GTK_WIDGET (grid)); -} - -static void -gtk_grid_forall (GtkContainer *container, - GtkCallback callback, - gpointer callback_data) -{ - GtkWidget *child; - - child = gtk_widget_get_first_child (GTK_WIDGET (container)); - while (child) - { - GtkWidget *next = gtk_widget_get_next_sibling (child); - - (* callback) (child, callback_data); - - child = next; - } -} - -static GType -gtk_grid_child_type (GtkContainer *container) -{ - return GTK_TYPE_WIDGET; -} - -static int -get_spacing (GtkGrid *grid, - GtkOrientation orientation) -{ - GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); - GtkCssValue *border_spacing; - gint css_spacing; - - border_spacing = _gtk_style_context_peek_property (gtk_widget_get_style_context (GTK_WIDGET (grid)), GTK_CSS_PROPERTY_BORDER_SPACING); - if (orientation == GTK_ORIENTATION_HORIZONTAL) - css_spacing = _gtk_css_position_value_get_x (border_spacing, 100); - else - css_spacing = _gtk_css_position_value_get_y (border_spacing, 100); - - return css_spacing + priv->linedata[orientation].spacing; -} - -/* Calculates the min and max numbers for both orientations. - */ -static void -gtk_grid_request_count_lines (GtkGridRequest *request) -{ - GtkWidget *child; - gint min[2]; - gint max[2]; - - min[0] = min[1] = G_MAXINT; - max[0] = max[1] = G_MININT; - - for (child = gtk_widget_get_first_child (GTK_WIDGET (request->grid)); - child != NULL; - child = gtk_widget_get_next_sibling (child)) - { - GtkGridChild *grid_child = get_grid_child (child); - GtkGridChildAttach *attach = grid_child->attach; - - min[0] = MIN (min[0], attach[0].pos); - max[0] = MAX (max[0], attach[0].pos + attach[0].span); - min[1] = MIN (min[1], attach[1].pos); - max[1] = MAX (max[1], attach[1].pos + attach[1].span); - } - - request->lines[0].min = min[0]; - request->lines[0].max = max[0]; - request->lines[1].min = min[1]; - request->lines[1].max = max[1]; -} - -/* Sets line sizes to 0 and marks lines as expand - * if they have a non-spanning expanding child. - */ -static void -gtk_grid_request_init (GtkGridRequest *request, - GtkOrientation orientation) -{ - GtkWidget *child; - GtkGridChildAttach *attach; - GtkGridLines *lines; - gint i; - - lines = &request->lines[orientation]; - - for (i = 0; i < lines->max - lines->min; i++) - { - lines->lines[i].minimum = 0; - lines->lines[i].natural = 0; - lines->lines[i].minimum_above = -1; - lines->lines[i].minimum_below = -1; - lines->lines[i].natural_above = -1; - lines->lines[i].natural_below = -1; - lines->lines[i].expand = FALSE; - lines->lines[i].empty = TRUE; - } - - - for (child = gtk_widget_get_first_child (GTK_WIDGET (request->grid)); - child != NULL; - child = gtk_widget_get_next_sibling (child)) - { - GtkGridChild *grid_child = get_grid_child (child); - - attach = &grid_child->attach[orientation]; - if (attach->span == 1 && gtk_widget_compute_expand (child, orientation)) - lines->lines[attach->pos - lines->min].expand = TRUE; - } -} - -/* Sums allocations for lines spanned by child and their spacing. - */ -static gint -compute_allocation_for_child (GtkGridRequest *request, - GtkGridChild *child, - GtkOrientation orientation) -{ - GtkGridLines *lines; - GtkGridLine *line; - GtkGridChildAttach *attach; - gint size; - gint i; - - lines = &request->lines[orientation]; - attach = &child->attach[orientation]; - - size = (attach->span - 1) * get_spacing (request->grid, orientation); - for (i = 0; i < attach->span; i++) - { - line = &lines->lines[attach->pos - lines->min + i]; - size += line->allocation; - } - - return size; -} - -static void -compute_request_for_child (GtkGridRequest *request, - GtkWidget *child, - GtkGridChild *grid_child, - GtkOrientation orientation, - gboolean contextual, - gint *minimum, - gint *natural, - gint *minimum_baseline, - gint *natural_baseline) -{ - if (minimum_baseline) - *minimum_baseline = -1; - if (natural_baseline) - *natural_baseline = -1; - - if (contextual) - { - gint size; - - size = compute_allocation_for_child (request, grid_child, 1 - orientation); - - gtk_widget_measure (child, - orientation, - size, - minimum, natural, - minimum_baseline, natural_baseline); - } - else - { - gtk_widget_measure (child, - orientation, - -1, - minimum, natural, - minimum_baseline, natural_baseline); - } -} - -/* Sets requisition to max. of non-spanning children. - * If contextual is TRUE, requires allocations of - * lines in the opposite orientation to be set. - */ -static void -gtk_grid_request_non_spanning (GtkGridRequest *request, - GtkOrientation orientation, - gboolean contextual) -{ - GtkWidget *child; - GtkGridChildAttach *attach; - GtkGridLines *lines; - GtkGridLine *line; - gint i; - GtkBaselinePosition baseline_pos; - gint minimum, minimum_baseline; - gint natural, natural_baseline; - - lines = &request->lines[orientation]; - - for (child = gtk_widget_get_first_child (GTK_WIDGET (request->grid)); - child != NULL; - child = gtk_widget_get_next_sibling (child)) - { - GtkGridChild *grid_child = get_grid_child (child); - - if (!_gtk_widget_get_visible (child)) - continue; - - attach = &grid_child->attach[orientation]; - if (attach->span != 1) - continue; - - compute_request_for_child (request, child, grid_child, orientation, contextual, &minimum, &natural, &minimum_baseline, &natural_baseline); - - line = &lines->lines[attach->pos - lines->min]; - - if (minimum_baseline != -1) - { - line->minimum_above = MAX (line->minimum_above, minimum_baseline); - line->minimum_below = MAX (line->minimum_below, minimum - minimum_baseline); - line->natural_above = MAX (line->natural_above, natural_baseline); - line->natural_below = MAX (line->natural_below, natural - natural_baseline); - } - else - { - line->minimum = MAX (line->minimum, minimum); - line->natural = MAX (line->natural, natural); - } - } - - for (i = 0; i < lines->max - lines->min; i++) - { - line = &lines->lines[i]; - - if (line->minimum_above != -1) - { - line->minimum = MAX (line->minimum, line->minimum_above + line->minimum_below); - line->natural = MAX (line->natural, line->natural_above + line->natural_below); - - baseline_pos = gtk_grid_get_row_baseline_position (request->grid, i + lines->min); - - switch (baseline_pos) - { - case GTK_BASELINE_POSITION_TOP: - line->minimum_above += 0; - line->minimum_below += line->minimum - (line->minimum_above + line->minimum_below); - line->natural_above += 0; - line->natural_below += line->natural - (line->natural_above + line->natural_below); - break; - case GTK_BASELINE_POSITION_CENTER: - line->minimum_above += (line->minimum - (line->minimum_above + line->minimum_below))/2; - line->minimum_below += (line->minimum - (line->minimum_above + line->minimum_below))/2; - line->natural_above += (line->natural - (line->natural_above + line->natural_below))/2; - line->natural_below += (line->natural - (line->natural_above + line->natural_below))/2; - break; - case GTK_BASELINE_POSITION_BOTTOM: - line->minimum_above += line->minimum - (line->minimum_above + line->minimum_below); - line->minimum_below += 0; - line->natural_above += line->natural - (line->natural_above + line->natural_below); - line->natural_below += 0; - break; - default: - break; - } - } - } -} - -/* Enforce homogeneous sizes. - */ -static void -gtk_grid_request_homogeneous (GtkGridRequest *request, - GtkOrientation orientation) -{ - GtkGridPrivate *priv = gtk_grid_get_instance_private (request->grid); - GtkGridLineData *linedata; - GtkGridLines *lines; - gint minimum, natural; - gint i; - - linedata = &priv->linedata[orientation]; - lines = &request->lines[orientation]; - - if (!linedata->homogeneous) - return; - - minimum = 0; - natural = 0; - - for (i = 0; i < lines->max - lines->min; i++) - { - minimum = MAX (minimum, lines->lines[i].minimum); - natural = MAX (natural, lines->lines[i].natural); - } - - for (i = 0; i < lines->max - lines->min; i++) - { - lines->lines[i].minimum = minimum; - lines->lines[i].natural = natural; - /* TODO: Do we want to adjust the baseline here too? - * And if so, also in the homogenous resize. - */ - } -} - -/* Deals with spanning children. - * Requires expand fields of lines to be set for - * non-spanning children. - */ -static void -gtk_grid_request_spanning (GtkGridRequest *request, - GtkOrientation orientation, - gboolean contextual) -{ - GtkGridPrivate *priv = gtk_grid_get_instance_private (request->grid); - GtkWidget *child; - GtkGridChildAttach *attach; - GtkGridLineData *linedata; - GtkGridLines *lines; - GtkGridLine *line; - gint minimum; - gint natural; - gint span_minimum; - gint span_natural; - gint span_expand; - gboolean force_expand; - gint spacing; - gint extra; - gint expand; - gint line_extra; - gint i; - - linedata = &priv->linedata[orientation]; - lines = &request->lines[orientation]; - spacing = get_spacing (request->grid, orientation); - - for (child = gtk_widget_get_first_child (GTK_WIDGET (request->grid)); - child != NULL; - child = gtk_widget_get_next_sibling (child)) - { - GtkGridChild *grid_child = get_grid_child (child); - - if (!_gtk_widget_get_visible (child)) - continue; - - attach = &grid_child->attach[orientation]; - if (attach->span == 1) - continue; - - /* We ignore baselines for spanning children */ - compute_request_for_child (request, child, grid_child, orientation, contextual, &minimum, &natural, NULL, NULL); - - span_minimum = (attach->span - 1) * spacing; - span_natural = (attach->span - 1) * spacing; - span_expand = 0; - force_expand = FALSE; - for (i = 0; i < attach->span; i++) - { - line = &lines->lines[attach->pos - lines->min + i]; - span_minimum += line->minimum; - span_natural += line->natural; - if (line->expand) - span_expand += 1; - } - if (span_expand == 0) - { - span_expand = attach->span; - force_expand = TRUE; - } - - /* If we need to request more space for this child to fill - * its requisition, then divide up the needed space amongst the - * lines it spans, favoring expandable lines if any. - * - * When doing homogeneous allocation though, try to keep the - * line allocations even, since we're going to force them to - * be the same anyway, and we don't want to introduce unnecessary - * extra space. - */ - if (span_minimum < minimum) - { - if (linedata->homogeneous) - { - gint total, m; - - total = minimum - (attach->span - 1) * spacing; - m = total / attach->span + (total % attach->span ? 1 : 0); - for (i = 0; i < attach->span; i++) - { - line = &lines->lines[attach->pos - lines->min + i]; - line->minimum = MAX(line->minimum, m); - } - } - else - { - extra = minimum - span_minimum; - expand = span_expand; - for (i = 0; i < attach->span; i++) - { - line = &lines->lines[attach->pos - lines->min + i]; - if (force_expand || line->expand) - { - line_extra = extra / expand; - line->minimum += line_extra; - extra -= line_extra; - expand -= 1; - } - } - } - } - - if (span_natural < natural) - { - if (linedata->homogeneous) - { - gint total, n; - - total = natural - (attach->span - 1) * spacing; - n = total / attach->span + (total % attach->span ? 1 : 0); - for (i = 0; i < attach->span; i++) - { - line = &lines->lines[attach->pos - lines->min + i]; - line->natural = MAX(line->natural, n); - } - } - else - { - extra = natural - span_natural; - expand = span_expand; - for (i = 0; i < attach->span; i++) - { - line = &lines->lines[attach->pos - lines->min + i]; - if (force_expand || line->expand) - { - line_extra = extra / expand; - line->natural += line_extra; - extra -= line_extra; - expand -= 1; - } - } - } - } - } -} - -/* Marks empty and expanding lines and counts them. - */ -static void -gtk_grid_request_compute_expand (GtkGridRequest *request, - GtkOrientation orientation, - gint min, - gint max, - gint *nonempty_lines, - gint *expand_lines) -{ - GtkWidget *child; - GtkGridChildAttach *attach; - gint i; - GtkGridLines *lines; - GtkGridLine *line; - gboolean has_expand; - gint expand; - gint empty; - - lines = &request->lines[orientation]; - - min = MAX (min, lines->min); - max = MIN (max, lines->max); - - for (i = min - lines->min; i < max - lines->min; i++) - { - lines->lines[i].need_expand = FALSE; - lines->lines[i].expand = FALSE; - lines->lines[i].empty = TRUE; - } - - for (child = gtk_widget_get_first_child (GTK_WIDGET (request->grid)); - child != NULL; - child = gtk_widget_get_next_sibling (child)) - { - GtkGridChild *grid_child = get_grid_child (child); - - if (!_gtk_widget_get_visible (child)) - continue; - - attach = &grid_child->attach[orientation]; - if (attach->span != 1) - continue; - - if (attach->pos >= max || attach->pos < min) - continue; - - line = &lines->lines[attach->pos - lines->min]; - line->empty = FALSE; - if (gtk_widget_compute_expand (child, orientation)) - line->expand = TRUE; - } - - for (child = gtk_widget_get_first_child (GTK_WIDGET (request->grid)); - child != NULL; - child = gtk_widget_get_next_sibling (child)) - { - GtkGridChild *grid_child = get_grid_child (child); - - if (!_gtk_widget_get_visible (child)) - continue; - - attach = &grid_child->attach[orientation]; - if (attach->span == 1) - continue; - - has_expand = FALSE; - for (i = 0; i < attach->span; i++) - { - line = &lines->lines[attach->pos - lines->min + i]; - - if (line->expand) - has_expand = TRUE; - - if (attach->pos + i >= max || attach->pos + 1 < min) - continue; - - line->empty = FALSE; - } - - if (!has_expand && gtk_widget_compute_expand (child, orientation)) - { - for (i = 0; i < attach->span; i++) - { - if (attach->pos + i >= max || attach->pos + 1 < min) - continue; - - line = &lines->lines[attach->pos - lines->min + i]; - line->need_expand = TRUE; - } - } - } - - empty = 0; - expand = 0; - for (i = min - lines->min; i < max - lines->min; i++) - { - line = &lines->lines[i]; - - if (line->need_expand) - line->expand = TRUE; - - if (line->empty) - empty += 1; - - if (line->expand) - expand += 1; - } - - if (nonempty_lines) - *nonempty_lines = max - min - empty; - - if (expand_lines) - *expand_lines = expand; -} - -/* Sums the minimum and natural fields of lines and their spacing. - */ -static void -gtk_grid_request_sum (GtkGridRequest *request, - GtkOrientation orientation, - gint *minimum, - gint *natural, - gint *minimum_baseline, - gint *natural_baseline) -{ - GtkGridPrivate *priv = gtk_grid_get_instance_private (request->grid); - GtkGridLines *lines; - gint i; - gint min, nat; - gint nonempty; - gint spacing; - - gtk_grid_request_compute_expand (request, orientation, G_MININT, G_MAXINT, &nonempty, NULL); - - lines = &request->lines[orientation]; - spacing = get_spacing (request->grid, orientation); - - min = 0; - nat = 0; - for (i = 0; i < lines->max - lines->min; i++) - { - if (orientation == GTK_ORIENTATION_VERTICAL && - lines->min + i == priv->baseline_row && - lines->lines[i].minimum_above != -1) - { - if (minimum_baseline) - *minimum_baseline = min + lines->lines[i].minimum_above; - if (natural_baseline) - *natural_baseline = nat + lines->lines[i].natural_above; - } - - min += lines->lines[i].minimum; - nat += lines->lines[i].natural; - - if (!lines->lines[i].empty) - { - min += spacing; - nat += spacing; - } - } - - /* Remove last spacing, if any was applied */ - if (nonempty > 0) - { - min -= spacing; - nat -= spacing; - } - - *minimum = min; - *natural = nat; -} - -/* Computes minimum and natural fields of lines. - * When contextual is TRUE, requires allocation of - * lines in the opposite orientation to be set. - */ -static void -gtk_grid_request_run (GtkGridRequest *request, - GtkOrientation orientation, - gboolean contextual) -{ - gtk_grid_request_init (request, orientation); - gtk_grid_request_non_spanning (request, orientation, contextual); - gtk_grid_request_homogeneous (request, orientation); - gtk_grid_request_spanning (request, orientation, contextual); - gtk_grid_request_homogeneous (request, orientation); -} - -static void -gtk_grid_distribute_non_homogeneous (GtkGridLines *lines, - gint nonempty, - gint expand, - gint size, - gint min, - gint max) -{ - GtkRequestedSize *sizes; - GtkGridLine *line; - gint extra; - gint rest; - int i, j; - - if (nonempty == 0) - return; - - sizes = g_newa (GtkRequestedSize, nonempty); - - j = 0; - for (i = min - lines->min; i < max - lines->min; i++) - { - line = &lines->lines[i]; - if (line->empty) - continue; - - size -= line->minimum; - - sizes[j].minimum_size = line->minimum; - sizes[j].natural_size = line->natural; - sizes[j].data = line; - j++; - } - - size = gtk_distribute_natural_allocation (MAX (0, size), nonempty, sizes); - - if (expand > 0) - { - extra = size / expand; - rest = size % expand; - } - else - { - extra = 0; - rest = 0; - } + case PROP_BASELINE_ROW: + g_value_set_int (value, gtk_grid_layout_get_baseline_row (GTK_GRID_LAYOUT (priv->layout_manager))); + break; - j = 0; - for (i = min - lines->min; i < max - lines->min; i++) - { - line = &lines->lines[i]; - if (line->empty) - continue; - - g_assert (line == sizes[j].data); - - line->allocation = sizes[j].minimum_size; - if (line->expand) - { - line->allocation += extra; - if (rest > 0) - { - line->allocation += 1; - rest -= 1; - } - } - - j++; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } } -/* Requires that the minimum and natural fields of lines - * have been set, computes the allocation field of lines - * by distributing total_size among lines. - */ static void -gtk_grid_request_allocate (GtkGridRequest *request, - GtkOrientation orientation, - gint total_size) +gtk_grid_set_orientation (GtkGrid *grid, + GtkOrientation orientation) { - GtkGridPrivate *priv = gtk_grid_get_instance_private (request->grid); - GtkGridLineData *linedata; - GtkGridLines *lines; - GtkGridLine *line; - gint nonempty1, nonempty2; - gint expand1, expand2; - gint i; - GtkBaselinePosition baseline_pos; - gint baseline; - gint extra, extra2; - gint rest; - gint size1, size2; - gint split, split_pos; - gint spacing; - - linedata = &priv->linedata[orientation]; - lines = &request->lines[orientation]; - spacing = get_spacing (request->grid, orientation); - - baseline = gtk_widget_get_allocated_baseline (GTK_WIDGET (request->grid)); - - if (orientation == GTK_ORIENTATION_VERTICAL && baseline != -1 && - priv->baseline_row >= lines->min && priv->baseline_row < lines->max && - lines->lines[priv->baseline_row - lines->min].minimum_above != -1) - { - split = priv->baseline_row; - split_pos = baseline - lines->lines[priv->baseline_row - lines->min].minimum_above; - gtk_grid_request_compute_expand (request, orientation, lines->min, split, &nonempty1, &expand1); - gtk_grid_request_compute_expand (request, orientation, split, lines->max, &nonempty2, &expand2); - - if (nonempty2 > 0) - { - size1 = split_pos - (nonempty1) * spacing; - size2 = (total_size - split_pos) - (nonempty2 - 1) * spacing; - } - else - { - size1 = total_size - (nonempty1 - 1) * spacing; - size2 = 0; - } - } - else - { - gtk_grid_request_compute_expand (request, orientation, lines->min, lines->max, &nonempty1, &expand1); - nonempty2 = expand2 = 0; - split = lines->max; - - size1 = total_size - (nonempty1 - 1) * spacing; - size2 = 0; - } - - if (nonempty1 == 0 && nonempty2 == 0) - return; + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); - if (linedata->homogeneous) - { - if (nonempty1 > 0) - { - extra = size1 / nonempty1; - rest = size1 % nonempty1; - } - else - { - extra = 0; - rest = 0; - } - if (nonempty2 > 0) - { - extra2 = size2 / nonempty2; - if (extra2 < extra || nonempty1 == 0) - { - extra = extra2; - rest = size2 % nonempty2; - } - } - - for (i = 0; i < lines->max - lines->min; i++) - { - line = &lines->lines[i]; - if (line->empty) - continue; - - line->allocation = extra; - if (rest > 0) - { - line->allocation += 1; - rest -= 1; - } - } - } - else + if (priv->orientation != orientation) { - gtk_grid_distribute_non_homogeneous (lines, - nonempty1, - expand1, - size1, - lines->min, - split); - gtk_grid_distribute_non_homogeneous (lines, - nonempty2, - expand2, - size2, - split, - lines->max); - } + priv->orientation = orientation; + _gtk_orientable_set_style_classes (GTK_ORIENTABLE (grid)); - for (i = 0; i < lines->max - lines->min; i++) - { - line = &lines->lines[i]; - if (line->empty) - continue; - - if (line->minimum_above != -1) - { - /* Note: This is overridden in gtk_grid_request_position for the allocated baseline */ - baseline_pos = gtk_grid_get_row_baseline_position (request->grid, i + lines->min); - - switch (baseline_pos) - { - case GTK_BASELINE_POSITION_TOP: - line->allocated_baseline = - line->minimum_above; - break; - case GTK_BASELINE_POSITION_CENTER: - line->allocated_baseline = - line->minimum_above + - (line->allocation - (line->minimum_above + line->minimum_below)) / 2; - break; - case GTK_BASELINE_POSITION_BOTTOM: - line->allocated_baseline = - line->allocation - line->minimum_below; - break; - default: - break; - } - } - else - line->allocated_baseline = -1; + g_object_notify (G_OBJECT (grid), "orientation"); } } -/* Computes the position fields from allocation and spacing. - */ static void -gtk_grid_request_position (GtkGridRequest *request, - GtkOrientation orientation) +gtk_grid_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - GtkGridPrivate *priv = gtk_grid_get_instance_private (request->grid); - GtkGridLines *lines; - GtkGridLine *line; - gint position, old_position; - int allocated_baseline; - gint spacing; - gint i, j; + GtkGrid *grid = GTK_GRID (object); - lines = &request->lines[orientation]; - spacing = get_spacing (request->grid, orientation); + switch (prop_id) + { + case PROP_ORIENTATION: + gtk_grid_set_orientation (grid, g_value_get_enum (value)); + break; - allocated_baseline = gtk_widget_get_allocated_baseline (GTK_WIDGET(request->grid)); + case PROP_ROW_SPACING: + gtk_grid_set_row_spacing (grid, g_value_get_int (value)); + break; - position = 0; - for (i = 0; i < lines->max - lines->min; i++) - { - line = &lines->lines[i]; - - if (orientation == GTK_ORIENTATION_VERTICAL && - i + lines->min == priv->baseline_row && - allocated_baseline != -1 && - lines->lines[i].minimum_above != -1) - { - old_position = position; - position = allocated_baseline - line->minimum_above; - - /* Back-patch previous rows */ - for (j = 0; j < i; j++) - { - if (!lines->lines[j].empty) - lines->lines[j].position += position - old_position; - } - } - - if (!line->empty) - { - line->position = position; - position += line->allocation + spacing; - - if (orientation == GTK_ORIENTATION_VERTICAL && - i + lines->min == priv->baseline_row && - allocated_baseline != -1 && - lines->lines[i].minimum_above != -1) - line->allocated_baseline = allocated_baseline - line->position; - } + case PROP_COLUMN_SPACING: + gtk_grid_set_column_spacing (grid, g_value_get_int (value)); + break; + + case PROP_ROW_HOMOGENEOUS: + gtk_grid_set_row_homogeneous (grid, g_value_get_boolean (value)); + break; + + case PROP_COLUMN_HOMOGENEOUS: + gtk_grid_set_column_homogeneous (grid, g_value_get_boolean (value)); + break; + + case PROP_BASELINE_ROW: + gtk_grid_set_baseline_row (grid, g_value_get_int (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } } static void -gtk_grid_get_size (GtkGrid *grid, - GtkOrientation orientation, - gint *minimum, - gint *natural, - gint *minimum_baseline, - gint *natural_baseline) +grid_attach (GtkGrid *grid, + GtkWidget *widget, + gint left, + gint top, + gint width, + gint height) { - GtkGridRequest request; - GtkGridLines *lines; + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + GtkGridLayoutChild *grid_child; - *minimum = 0; - *natural = 0; + gtk_widget_set_parent (widget, GTK_WIDGET (grid)); - if (minimum_baseline) - *minimum_baseline = -1; + grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, widget)); + gtk_grid_layout_child_set_left_attach (grid_child, left); + gtk_grid_layout_child_set_top_attach (grid_child, top); + gtk_grid_layout_child_set_column_span (grid_child, width); + gtk_grid_layout_child_set_row_span (grid_child, height); +} - if (natural_baseline) - *natural_baseline = -1; +/* Find the position 'touching' existing + * children. @orientation and @max determine + * from which direction to approach (horizontal + * + max = right, vertical + !max = top, etc). + * @op_pos, @op_span determine the rows/columns + * in which the touching has to happen. + */ +static gint +find_attach_position (GtkGrid *grid, + GtkOrientation orientation, + gint op_pos, + gint op_span, + gboolean max) +{ + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + GtkWidget *child; + gboolean hit; + gint pos; - if (gtk_widget_get_first_child (GTK_WIDGET (grid)) == NULL) - return; + if (max) + pos = -G_MAXINT; + else + pos = G_MAXINT; - request.grid = grid; - gtk_grid_request_count_lines (&request); - lines = &request.lines[orientation]; - lines->lines = g_newa (GtkGridLine, lines->max - lines->min); - memset (lines->lines, 0, (lines->max - lines->min) * sizeof (GtkGridLine)); + hit = FALSE; - gtk_grid_request_run (&request, orientation, FALSE); - gtk_grid_request_sum (&request, orientation, minimum, natural, - minimum_baseline, natural_baseline); -} + for (child = gtk_widget_get_first_child (GTK_WIDGET (grid)); + child != NULL; + child = gtk_widget_get_next_sibling (child)) + { + GtkGridLayoutChild *grid_child; + int attach_pos = 0, attach_span = 0; + int opposite_pos = 0, opposite_span = 0; -static void -gtk_grid_get_size_for_size (GtkGrid *grid, - GtkOrientation orientation, - gint size, - gint *minimum, - gint *natural, - gint *minimum_baseline, - gint *natural_baseline) -{ - GtkGridRequest request; - GtkGridLines *lines; - gint min_size, nat_size; + grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child)); - *minimum = 0; - *natural = 0; + switch (orientation) + { + case GTK_ORIENTATION_HORIZONTAL: + attach_pos = gtk_grid_layout_child_get_left_attach (grid_child); + attach_span = gtk_grid_layout_child_get_column_span (grid_child); + opposite_pos = gtk_grid_layout_child_get_top_attach (grid_child); + opposite_span = gtk_grid_layout_child_get_row_span (grid_child); + break; - if (minimum_baseline) - *minimum_baseline = -1; + case GTK_ORIENTATION_VERTICAL: + attach_pos = gtk_grid_layout_child_get_top_attach (grid_child); + attach_span = gtk_grid_layout_child_get_row_span (grid_child); + opposite_pos = gtk_grid_layout_child_get_left_attach (grid_child); + opposite_span = gtk_grid_layout_child_get_column_span (grid_child); + break; - if (natural_baseline) - *natural_baseline = -1; + default: + break; + } - if (gtk_widget_get_first_child (GTK_WIDGET (grid)) == NULL) - return; + /* check if the ranges overlap */ + if (opposite_pos <= op_pos + op_span && op_pos <= opposite_pos + opposite_span) + { + hit = TRUE; - request.grid = grid; - gtk_grid_request_count_lines (&request); - lines = &request.lines[0]; - lines->lines = g_newa (GtkGridLine, lines->max - lines->min); - memset (lines->lines, 0, (lines->max - lines->min) * sizeof (GtkGridLine)); - lines = &request.lines[1]; - lines->lines = g_newa (GtkGridLine, lines->max - lines->min); - memset (lines->lines, 0, (lines->max - lines->min) * sizeof (GtkGridLine)); + if (max) + pos = MAX (pos, attach_pos + attach_span); + else + pos = MIN (pos, attach_pos); + } + } - gtk_grid_request_run (&request, 1 - orientation, FALSE); - gtk_grid_request_sum (&request, 1 - orientation, &min_size, &nat_size, NULL, NULL); - gtk_grid_request_allocate (&request, 1 - orientation, MAX (size, min_size)); + if (!hit) + pos = 0; - gtk_grid_request_run (&request, orientation, TRUE); - gtk_grid_request_sum (&request, orientation, minimum, natural, minimum_baseline, natural_baseline); + return pos; } static void -gtk_grid_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline) +gtk_grid_add (GtkContainer *container, + GtkWidget *child) { - GtkGrid *grid = GTK_GRID (widget); + GtkGrid *grid = GTK_GRID (container); + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + gint pos[2] = { 0, 0 }; - if ((orientation == GTK_ORIENTATION_HORIZONTAL && - gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT) || - (orientation == GTK_ORIENTATION_VERTICAL && - gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)) - gtk_grid_get_size_for_size (grid, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline); - else - gtk_grid_get_size (grid, orientation, minimum, natural, minimum_baseline, natural_baseline); + pos[priv->orientation] = find_attach_position (grid, priv->orientation, 0, 1, TRUE); + grid_attach (grid, child, pos[0], pos[1], 1, 1); } static void -allocate_child (GtkGridRequest *request, - GtkOrientation orientation, - GtkWidget *child, - GtkGridChild *grid_child, - gint *position, - gint *size, - gint *baseline) +gtk_grid_remove (GtkContainer *container, + GtkWidget *child) { - GtkGridLines *lines; - GtkGridLine *line; - GtkGridChildAttach *attach; - gint i; - - lines = &request->lines[orientation]; - attach = &grid_child->attach[orientation]; + GtkGrid *grid = GTK_GRID (container); + gboolean was_visible; - *position = lines->lines[attach->pos - lines->min].position; - if (attach->span == 1 && gtk_widget_get_valign (child) == GTK_ALIGN_BASELINE) - *baseline = lines->lines[attach->pos - lines->min].allocated_baseline; - else - *baseline = -1; + was_visible = _gtk_widget_get_visible (child); + gtk_widget_unparent (child); - *size = (attach->span - 1) * get_spacing (request->grid, orientation); - for (i = 0; i < attach->span; i++) - { - line = &lines->lines[attach->pos - lines->min + i]; - *size += line->allocation; - } + if (was_visible && _gtk_widget_get_visible (GTK_WIDGET (grid))) + gtk_widget_queue_resize (GTK_WIDGET (grid)); } static void -gtk_grid_request_allocate_children (GtkGridRequest *request, - int grid_width, - int grid_height) +gtk_grid_forall (GtkContainer *container, + GtkCallback callback, + gpointer callback_data) { GtkWidget *child; - GtkAllocation child_allocation; - gint x, y, width, height, baseline, ignore; - - for (child = gtk_widget_get_first_child (GTK_WIDGET (request->grid)); - child != NULL; - child = gtk_widget_get_next_sibling (child)) + child = gtk_widget_get_first_child (GTK_WIDGET (container)); + while (child) { - GtkGridChild *grid_child = get_grid_child (child); - - if (!_gtk_widget_get_visible (child)) - continue; - - allocate_child (request, GTK_ORIENTATION_HORIZONTAL, child, grid_child, &x, &width, &ignore); - allocate_child (request, GTK_ORIENTATION_VERTICAL, child, grid_child, &y, &height, &baseline); - - child_allocation.x = x; - child_allocation.y = y; - child_allocation.width = width; - child_allocation.height = height; + GtkWidget *next = gtk_widget_get_next_sibling (child); - if (_gtk_widget_get_direction (GTK_WIDGET (request->grid)) == GTK_TEXT_DIR_RTL) - child_allocation.x = grid_width - child_allocation.x - child_allocation.width; + (* callback) (child, callback_data); - gtk_widget_size_allocate (child, &child_allocation, baseline); + child = next; } } -#define GET_SIZE(width, height, orientation) (orientation == GTK_ORIENTATION_HORIZONTAL ? width : height) - -static void -gtk_grid_size_allocate (GtkWidget *widget, - int width, - int height, - int baseline) +static GType +gtk_grid_child_type (GtkContainer *container) { - GtkGrid *grid = GTK_GRID (widget); - GtkGridRequest request; - GtkGridLines *lines; - GtkOrientation orientation; - - if (gtk_widget_get_first_child (widget) == NULL) - return; - - request.grid = grid; - - gtk_grid_request_count_lines (&request); - lines = &request.lines[0]; - lines->lines = g_newa (GtkGridLine, lines->max - lines->min); - memset (lines->lines, 0, (lines->max - lines->min) * sizeof (GtkGridLine)); - lines = &request.lines[1]; - lines->lines = g_newa (GtkGridLine, lines->max - lines->min); - memset (lines->lines, 0, (lines->max - lines->min) * sizeof (GtkGridLine)); - - if (gtk_widget_get_request_mode (widget) == GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT) - orientation = GTK_ORIENTATION_HORIZONTAL; - else - orientation = GTK_ORIENTATION_VERTICAL; - - gtk_grid_request_run (&request, 1 - orientation, FALSE); - gtk_grid_request_allocate (&request, 1 - orientation, GET_SIZE (width, height, 1 - orientation)); - gtk_grid_request_run (&request, orientation, TRUE); - - gtk_grid_request_allocate (&request, orientation, GET_SIZE (width, height, orientation)); - - gtk_grid_request_position (&request, 0); - gtk_grid_request_position (&request, 1); - - gtk_grid_request_allocate_children (&request, width, height); + return GTK_TYPE_WIDGET; } static void @@ -1602,17 +334,11 @@ gtk_grid_class_init (GtkGridClass *class) object_class->get_property = gtk_grid_get_property; object_class->set_property = gtk_grid_set_property; - object_class->finalize = gtk_grid_finalize; - - widget_class->size_allocate = gtk_grid_size_allocate; - widget_class->measure = gtk_grid_measure; container_class->add = gtk_grid_add; container_class->remove = gtk_grid_remove; container_class->forall = gtk_grid_forall; container_class->child_type = gtk_grid_child_type; - container_class->set_child_property = gtk_grid_set_child_property; - container_class->get_child_property = gtk_grid_get_child_property; g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation"); @@ -1651,41 +377,8 @@ gtk_grid_class_init (GtkGridClass *class) 0, G_MAXINT, 0, GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); - g_object_class_install_properties (object_class, - N_PROPERTIES, - obj_properties); - - child_properties[CHILD_PROP_LEFT_ATTACH] = - g_param_spec_int ("left-attach", - P_("Left attachment"), - P_("The column number to attach the left side of the child to"), - G_MININT, G_MAXINT, 0, - GTK_PARAM_READWRITE); - - child_properties[CHILD_PROP_TOP_ATTACH] = - g_param_spec_int ("top-attach", - P_("Top attachment"), - P_("The row number to attach the top side of a child widget to"), - G_MININT, G_MAXINT, 0, - GTK_PARAM_READWRITE); - - child_properties[CHILD_PROP_WIDTH] = - g_param_spec_int ("width", - P_("Width"), - P_("The number of columns that a child spans"), - 1, G_MAXINT, 1, - GTK_PARAM_READWRITE); - - child_properties[CHILD_PROP_HEIGHT] = - g_param_spec_int ("height", - P_("Height"), - P_("The number of rows that a child spans"), - 1, G_MAXINT, 1, - GTK_PARAM_READWRITE); - - - gtk_container_class_install_child_properties (container_class, N_CHILD_PROPERTIES, child_properties); - child_data_quark = g_quark_from_static_string ("gtk-grid-child-data"); + g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); + gtk_widget_class_set_css_name (widget_class, I_("grid")); } @@ -1696,15 +389,10 @@ gtk_grid_init (GtkGrid *grid) gtk_widget_set_has_surface (GTK_WIDGET (grid), FALSE); - priv->orientation = GTK_ORIENTATION_HORIZONTAL; - priv->baseline_row = 0; - - priv->linedata[0].spacing = 0; - priv->linedata[1].spacing = 0; - - priv->linedata[0].homogeneous = FALSE; - priv->linedata[1].homogeneous = FALSE; + priv->layout_manager = gtk_grid_layout_new (); + gtk_widget_set_layout_manager (GTK_WIDGET (grid), priv->layout_manager); + priv->orientation = GTK_ORIENTATION_HORIZONTAL; _gtk_orientable_set_style_classes (GTK_ORIENTABLE (grid)); } @@ -1781,7 +469,8 @@ gtk_grid_attach_next_to (GtkGrid *grid, gint width, gint height) { - GtkGridChild *grid_sibling; + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + GtkGridLayoutChild *grid_sibling; gint left, top; g_return_if_fail (GTK_IS_GRID (grid)); @@ -1791,27 +480,29 @@ gtk_grid_attach_next_to (GtkGrid *grid, g_return_if_fail (width > 0); g_return_if_fail (height > 0); - if (sibling) + if (sibling != NULL) { - grid_sibling = get_grid_child (sibling); + grid_sibling = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, sibling)); switch (side) { case GTK_POS_LEFT: - left = CHILD_LEFT (grid_sibling) - width; - top = CHILD_TOP (grid_sibling); + left = gtk_grid_layout_child_get_left_attach (grid_sibling) - width; + top = gtk_grid_layout_child_get_top_attach (grid_sibling); break; case GTK_POS_RIGHT: - left = CHILD_LEFT (grid_sibling) + CHILD_WIDTH (grid_sibling); - top = CHILD_TOP (grid_sibling); + left = gtk_grid_layout_child_get_left_attach (grid_sibling) + + gtk_grid_layout_child_get_column_span (grid_sibling); + top = gtk_grid_layout_child_get_top_attach (grid_sibling); break; case GTK_POS_TOP: - left = CHILD_LEFT (grid_sibling); - top = CHILD_TOP (grid_sibling) - height; + left = gtk_grid_layout_child_get_left_attach (grid_sibling); + top = gtk_grid_layout_child_get_top_attach (grid_sibling) - height; break; case GTK_POS_BOTTOM: - left = CHILD_LEFT (grid_sibling); - top = CHILD_TOP (grid_sibling) + CHILD_HEIGHT (grid_sibling); + left = gtk_grid_layout_child_get_left_attach (grid_sibling); + top = gtk_grid_layout_child_get_top_attach (grid_sibling) + + gtk_grid_layout_child_get_row_span (grid_sibling); break; default: g_assert_not_reached (); @@ -1863,6 +554,7 @@ gtk_grid_get_child_at (GtkGrid *grid, gint left, gint top) { + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); GtkWidget *child; g_return_val_if_fail (GTK_IS_GRID (grid), NULL); @@ -1871,12 +563,19 @@ gtk_grid_get_child_at (GtkGrid *grid, child != NULL; child = gtk_widget_get_next_sibling (child)) { - GtkGridChild *grid_child = get_grid_child (child); - - if (CHILD_LEFT (grid_child) <= left && - CHILD_LEFT (grid_child) + CHILD_WIDTH (grid_child) > left && - CHILD_TOP (grid_child) <= top && - CHILD_TOP (grid_child) + CHILD_HEIGHT (grid_child) > top) + GtkGridLayoutChild *grid_child; + int child_left, child_top, child_width, child_height; + + grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child)); + child_left = gtk_grid_layout_child_get_left_attach (grid_child); + child_top = gtk_grid_layout_child_get_top_attach (grid_child); + child_width = gtk_grid_layout_child_get_column_span (grid_child); + child_height = gtk_grid_layout_child_get_row_span (grid_child); + + if (child_left <= left && + child_left + child_width > left && + child_top <= top && + child_top + child_height > top) return child; } @@ -1901,7 +600,6 @@ gtk_grid_insert_row (GtkGrid *grid, GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); GtkWidget *child; int top, height; - GList *list; g_return_if_fail (GTK_IS_GRID (grid)); @@ -1909,33 +607,16 @@ gtk_grid_insert_row (GtkGrid *grid, child != NULL; child = gtk_widget_get_next_sibling (child)) { - GtkGridChild *grid_child = get_grid_child (child); - - top = CHILD_TOP (grid_child); - height = CHILD_HEIGHT (grid_child); + GtkGridLayoutChild *grid_child; + + grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child)); + top = gtk_grid_layout_child_get_top_attach (grid_child); + height = gtk_grid_layout_child_get_row_span (grid_child); if (top >= position) - { - CHILD_TOP (grid_child) = top + 1; - gtk_container_child_notify_by_pspec (GTK_CONTAINER (grid), - child, - child_properties[CHILD_PROP_TOP_ATTACH]); - } + gtk_grid_layout_child_set_top_attach (grid_child, top + 1); else if (top + height > position) - { - CHILD_HEIGHT (grid_child) = height + 1; - gtk_container_child_notify_by_pspec (GTK_CONTAINER (grid), - child, - child_properties[CHILD_PROP_HEIGHT]); - } - } - - for (list = priv->row_properties; list != NULL; list = list->next) - { - GtkGridRowProperties *prop = list->data; - - if (prop->row >= position) - prop->row += 1; + gtk_grid_layout_child_set_row_span (grid_child, height + 1); } } @@ -1955,7 +636,7 @@ void gtk_grid_remove_row (GtkGrid *grid, gint position) { - int top, height; + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); GtkWidget *child; g_return_if_fail (GTK_IS_GRID (grid)); @@ -1963,11 +644,13 @@ gtk_grid_remove_row (GtkGrid *grid, child = gtk_widget_get_first_child (GTK_WIDGET (grid)); while (child) { - GtkGridChild *grid_child = get_grid_child (child); GtkWidget *next = gtk_widget_get_next_sibling (child); + GtkGridLayoutChild *grid_child; + int top, height; - top = CHILD_TOP (grid_child); - height = CHILD_HEIGHT (grid_child); + grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child)); + top = gtk_grid_layout_child_get_top_attach (grid_child); + height = gtk_grid_layout_child_get_row_span (grid_child); if (top <= position && top + height > position) height--; @@ -1975,12 +658,15 @@ gtk_grid_remove_row (GtkGrid *grid, top--; if (height <= 0) - gtk_container_remove (GTK_CONTAINER (grid), child); + { + gtk_container_remove (GTK_CONTAINER (grid), child); + } else - gtk_container_child_set (GTK_CONTAINER (grid), child, - "height", height, - "top-attach", top, - NULL); + { + gtk_grid_layout_child_set_row_span (grid_child, height); + gtk_grid_layout_child_set_top_attach (grid_child, top); + } + child = next; } } @@ -2000,8 +686,8 @@ void gtk_grid_insert_column (GtkGrid *grid, gint position) { + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); GtkWidget *child; - int left, width; g_return_if_fail (GTK_IS_GRID (grid)); @@ -2009,25 +695,17 @@ gtk_grid_insert_column (GtkGrid *grid, child != NULL; child = gtk_widget_get_next_sibling (child)) { - GtkGridChild *grid_child = get_grid_child (child); + GtkGridLayoutChild *grid_child; + int left, width; - left = CHILD_LEFT (grid_child); - width = CHILD_WIDTH (grid_child); + grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child)); + left = gtk_grid_layout_child_get_left_attach (grid_child); + width = gtk_grid_layout_child_get_column_span (grid_child); if (left >= position) - { - CHILD_LEFT (grid_child) = left + 1; - gtk_container_child_notify_by_pspec (GTK_CONTAINER (grid), - child, - child_properties[CHILD_PROP_LEFT_ATTACH]); - } + gtk_grid_layout_child_set_left_attach (grid_child, left + 1); else if (left + width > position) - { - CHILD_WIDTH (grid_child) = width + 1; - gtk_container_child_notify_by_pspec (GTK_CONTAINER (grid), - child, - child_properties[CHILD_PROP_WIDTH]); - } + gtk_grid_layout_child_set_column_span (grid_child, width + 1); } } @@ -2047,19 +725,22 @@ void gtk_grid_remove_column (GtkGrid *grid, gint position) { + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); GtkWidget *child; - int left, width; g_return_if_fail (GTK_IS_GRID (grid)); child = gtk_widget_get_first_child (GTK_WIDGET (grid)); while (child) { - GtkGridChild *grid_child = get_grid_child (child); GtkWidget *next = gtk_widget_get_next_sibling (child); + GtkGridLayoutChild *grid_child; + int left, width; - left = CHILD_LEFT (grid_child); - width = CHILD_WIDTH (grid_child); + grid_child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, child)); + + left = gtk_grid_layout_child_get_left_attach (grid_child); + width = gtk_grid_layout_child_get_column_span (grid_child); if (left <= position && left + width > position) width--; @@ -2067,12 +748,14 @@ gtk_grid_remove_column (GtkGrid *grid, left--; if (width <= 0) - gtk_container_remove (GTK_CONTAINER (grid), child); + { + gtk_container_remove (GTK_CONTAINER (grid), child); + } else - gtk_container_child_set (GTK_CONTAINER (grid), child, - "width", width, - "left-attach", left, - NULL); + { + gtk_grid_layout_child_set_column_span (grid_child, width); + gtk_grid_layout_child_set_left_attach (grid_child, left); + } child = next; } @@ -2097,27 +780,36 @@ gtk_grid_insert_next_to (GtkGrid *grid, GtkWidget *sibling, GtkPositionType side) { - GtkGridChild *child; + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + GtkGridLayoutChild *child; g_return_if_fail (GTK_IS_GRID (grid)); g_return_if_fail (GTK_IS_WIDGET (sibling)); g_return_if_fail (_gtk_widget_get_parent (sibling) == (GtkWidget*)grid); - child = get_grid_child (sibling); + child = GTK_GRID_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (priv->layout_manager, sibling)); switch (side) { case GTK_POS_LEFT: - gtk_grid_insert_column (grid, CHILD_LEFT (child)); + gtk_grid_insert_column (grid, gtk_grid_layout_child_get_left_attach (child)); break; case GTK_POS_RIGHT: - gtk_grid_insert_column (grid, CHILD_LEFT (child) + CHILD_WIDTH (child)); + { + int col = gtk_grid_layout_child_get_left_attach (child) + + gtk_grid_layout_child_get_column_span (child); + gtk_grid_insert_column (grid, col); + } break; case GTK_POS_TOP: - gtk_grid_insert_row (grid, CHILD_TOP (child)); + gtk_grid_insert_row (grid, gtk_grid_layout_child_get_top_attach (child)); break; case GTK_POS_BOTTOM: - gtk_grid_insert_row (grid, CHILD_TOP (child) + CHILD_HEIGHT (child)); + { + int row = gtk_grid_layout_child_get_top_attach (child) + + gtk_grid_layout_child_get_row_span (child); + gtk_grid_insert_row (grid, row); + } break; default: g_assert_not_reached (); @@ -2136,16 +828,14 @@ gtk_grid_set_row_homogeneous (GtkGrid *grid, gboolean homogeneous) { GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + gboolean old_val; + g_return_if_fail (GTK_IS_GRID (grid)); - /* Yes, homogeneous rows means all the columns have the same size */ - if (COLUMNS (priv)->homogeneous != homogeneous) + old_val = gtk_grid_layout_get_row_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager)); + if (old_val != !!homogeneous) { - COLUMNS (priv)->homogeneous = homogeneous; - - if (_gtk_widget_get_visible (GTK_WIDGET (grid))) - gtk_widget_queue_resize (GTK_WIDGET (grid)); - + gtk_grid_layout_set_row_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager), homogeneous); g_object_notify_by_pspec (G_OBJECT (grid), obj_properties [PROP_ROW_HOMOGENEOUS]); } } @@ -2162,9 +852,10 @@ gboolean gtk_grid_get_row_homogeneous (GtkGrid *grid) { GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + g_return_val_if_fail (GTK_IS_GRID (grid), FALSE); - return COLUMNS (priv)->homogeneous; + return gtk_grid_layout_get_row_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager)); } /** @@ -2179,16 +870,14 @@ gtk_grid_set_column_homogeneous (GtkGrid *grid, gboolean homogeneous) { GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + gboolean old_val; + g_return_if_fail (GTK_IS_GRID (grid)); - /* Yes, homogeneous columns means all the rows have the same size */ - if (ROWS (priv)->homogeneous != homogeneous) + old_val = gtk_grid_layout_get_column_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager)); + if (old_val != !!homogeneous) { - ROWS (priv)->homogeneous = homogeneous; - - if (_gtk_widget_get_visible (GTK_WIDGET (grid))) - gtk_widget_queue_resize (GTK_WIDGET (grid)); - + gtk_grid_layout_set_column_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager), homogeneous); g_object_notify_by_pspec (G_OBJECT (grid), obj_properties [PROP_COLUMN_HOMOGENEOUS]); } } @@ -2205,9 +894,10 @@ gboolean gtk_grid_get_column_homogeneous (GtkGrid *grid) { GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + g_return_val_if_fail (GTK_IS_GRID (grid), FALSE); - return ROWS (priv)->homogeneous; + return gtk_grid_layout_get_column_homogeneous (GTK_GRID_LAYOUT (priv->layout_manager)); } /** @@ -2222,16 +912,15 @@ gtk_grid_set_row_spacing (GtkGrid *grid, guint spacing) { GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + guint old_spacing; + g_return_if_fail (GTK_IS_GRID (grid)); g_return_if_fail (spacing <= G_MAXINT16); - if (COLUMNS (priv)->spacing != spacing) + old_spacing = gtk_grid_layout_get_row_spacing (GTK_GRID_LAYOUT (priv->layout_manager)); + if (old_spacing != spacing) { - COLUMNS (priv)->spacing = spacing; - - if (_gtk_widget_get_visible (GTK_WIDGET (grid))) - gtk_widget_queue_resize (GTK_WIDGET (grid)); - + gtk_grid_layout_set_row_spacing (GTK_GRID_LAYOUT (priv->layout_manager), spacing); g_object_notify_by_pspec (G_OBJECT (grid), obj_properties [PROP_ROW_SPACING]); } } @@ -2248,9 +937,10 @@ guint gtk_grid_get_row_spacing (GtkGrid *grid) { GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + g_return_val_if_fail (GTK_IS_GRID (grid), 0); - return COLUMNS (priv)->spacing; + return gtk_grid_layout_get_row_spacing (GTK_GRID_LAYOUT (priv->layout_manager)); } /** @@ -2265,16 +955,15 @@ gtk_grid_set_column_spacing (GtkGrid *grid, guint spacing) { GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + guint old_spacing; + g_return_if_fail (GTK_IS_GRID (grid)); g_return_if_fail (spacing <= G_MAXINT16); - if (ROWS (priv)->spacing != spacing) + old_spacing = gtk_grid_layout_get_column_spacing (GTK_GRID_LAYOUT (priv->layout_manager)); + if (old_spacing != spacing) { - ROWS (priv)->spacing = spacing; - - if (_gtk_widget_get_visible (GTK_WIDGET (grid))) - gtk_widget_queue_resize (GTK_WIDGET (grid)); - + gtk_grid_layout_set_column_spacing (GTK_GRID_LAYOUT (priv->layout_manager), spacing); g_object_notify_by_pspec (G_OBJECT (grid), obj_properties [PROP_COLUMN_SPACING]); } } @@ -2294,63 +983,7 @@ gtk_grid_get_column_spacing (GtkGrid *grid) g_return_val_if_fail (GTK_IS_GRID (grid), 0); - return ROWS (priv)->spacing; -} - -static GtkGridRowProperties * -find_row_properties (GtkGrid *grid, - gint row) -{ - GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); - GList *l; - - for (l = priv->row_properties; l != NULL; l = l->next) - { - GtkGridRowProperties *prop = l->data; - if (prop->row == row) - return prop; - } - - return NULL; -} - -static void -gtk_grid_row_properties_free (GtkGridRowProperties *props) -{ - g_slice_free (GtkGridRowProperties, props); -} - -static GtkGridRowProperties * -get_row_properties_or_create (GtkGrid *grid, - gint row) -{ - GtkGridRowProperties *props; - GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); - - props = find_row_properties (grid, row); - if (props) - return props; - - props = g_slice_new (GtkGridRowProperties); - *props = gtk_grid_row_properties_default; - props->row = row; - - priv->row_properties = - g_list_prepend (priv->row_properties, props); - - return props; -} - -static const GtkGridRowProperties * -get_row_properties_or_default (GtkGrid *grid, - gint row) -{ - GtkGridRowProperties *props; - - props = find_row_properties (grid, row); - if (props) - return props; - return >k_grid_row_properties_default; + return gtk_grid_layout_get_column_spacing (GTK_GRID_LAYOUT (priv->layout_manager)); } /** @@ -2367,19 +1000,13 @@ gtk_grid_set_row_baseline_position (GtkGrid *grid, gint row, GtkBaselinePosition pos) { - GtkGridRowProperties *props; + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); g_return_if_fail (GTK_IS_GRID (grid)); - props = get_row_properties_or_create (grid, row); - - if (props->baseline_position != pos) - { - props->baseline_position = pos; - - if (_gtk_widget_get_visible (GTK_WIDGET (grid))) - gtk_widget_queue_resize (GTK_WIDGET (grid)); - } + gtk_grid_layout_set_row_baseline_position (GTK_GRID_LAYOUT (priv->layout_manager), + row, + pos); } /** @@ -2397,13 +1024,11 @@ GtkBaselinePosition gtk_grid_get_row_baseline_position (GtkGrid *grid, gint row) { - const GtkGridRowProperties *props; + GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); g_return_val_if_fail (GTK_IS_GRID (grid), GTK_BASELINE_POSITION_CENTER); - props = get_row_properties_or_default (grid, row); - - return props->baseline_position; + return gtk_grid_layout_get_row_baseline_position (GTK_GRID_LAYOUT (priv->layout_manager), row); } /** @@ -2421,15 +1046,14 @@ gtk_grid_set_baseline_row (GtkGrid *grid, gint row) { GtkGridPrivate *priv = gtk_grid_get_instance_private (grid); + int old_row; g_return_if_fail (GTK_IS_GRID (grid)); - if (priv->baseline_row != row) + old_row = gtk_grid_layout_get_baseline_row (GTK_GRID_LAYOUT (priv->layout_manager)); + if (old_row != row) { - priv->baseline_row = row; - - if (_gtk_widget_get_visible (GTK_WIDGET (grid))) - gtk_widget_queue_resize (GTK_WIDGET (grid)); + gtk_grid_layout_set_baseline_row (GTK_GRID_LAYOUT (priv->layout_manager), row); g_object_notify (G_OBJECT (grid), "baseline-row"); } } @@ -2449,5 +1073,5 @@ gtk_grid_get_baseline_row (GtkGrid *grid) g_return_val_if_fail (GTK_IS_GRID (grid), 0); - return priv->baseline_row; + return gtk_grid_layout_get_baseline_row (GTK_GRID_LAYOUT (priv->layout_manager)); } -- 2.30.2